{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 四类参数\n",
    "- 普通参数\n",
    "- 默认参数\n",
    "- 关键字参数\n",
    "- 收集参数\n",
    "\n",
    "## 关键字参数\n",
    "- 语法\n",
    "\n",
    "      def func(p1=v1, p2=v2....):\n",
    "         func_body\n",
    "      \n",
    "      调用函数：\n",
    "      func(p1=value1, p2=value2....)\n",
    "- 调用比较麻烦，但也有好处\n",
    "    - 不容易混淆，一般形参和形参只是按照位置一一对应即可，容易出错；\n",
    "    - 使用关键字参数，可以不考虑参数位置；"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am student\n",
      "我叫小太阳，我今年18岁，我住我家\n",
      "I am student\n",
      "我叫小太阳，我今年18岁，我住我家\n"
     ]
    }
   ],
   "source": [
    "# 关键字参数案例\n",
    "def stu(name, age, addr):\n",
    "    print(\"I am student\")\n",
    "    print(\"我叫{0}，我今年{1}岁，我住{2}\".format(name, age, addr))\n",
    "    \n",
    "n = \"小太阳\"\n",
    "a = 18\n",
    "addr = \"我家\"\n",
    "\n",
    "# 普通参数，只按照位置传递，容易出错\n",
    "stu(n, a, addr)\n",
    "\n",
    "def stu_key(name=\"No Name\", age=0, addr=\"No addr\"):\n",
    "    print(\"I am student\")\n",
    "    print(\"我叫{0}，我今年{1}岁，我住{2}\".format(name, age, addr))\n",
    "    \n",
    "n = \"小太阳\"\n",
    "a = 18\n",
    "addr = \"我家\"\n",
    "\n",
    "# 普通参数，只按照位置传递，容易出错\n",
    "stu(name=n, age=a, addr=addr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 收集参数\n",
    "- 把没有位置，不能和定义时参数位置相对应的参数，放入一个待定的数据结构中；\n",
    "- 语法\n",
    "\n",
    "        def func(*args):\n",
    "           func_body\n",
    "           按照List使用方式访问args得到传入的参数\n",
    "           \n",
    "        调用:\n",
    "        func(p1, p2, p3, ....)\n",
    "- 参数名args不是必须这么些，但是，我们推荐使用args，约定俗称；\n",
    "- 参数名args前需要有星号（*）；\n",
    "- 收集参数可以和其他参数共存；\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'tuple'>\n",
      "Moose\n",
      "18\n",
      "郑州\n",
      "小太阳\n",
      "<class 'tuple'>\n",
      "某某人\n",
      "<class 'tuple'>\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "stu() got an unexpected keyword argument 'name'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-21-e1b625c97464>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[0mstu\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m \u001b[1;31m# 如果使用关键字参数格式调用，会出现问题\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m \u001b[0mstu\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"Moos\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: stu() got an unexpected keyword argument 'name'"
     ]
    }
   ],
   "source": [
    "# 收集参数代码\n",
    "def stu(*args):\n",
    "    print(type(args))\n",
    "    for arg in args:\n",
    "        print(arg)\n",
    "\n",
    "stu(\"Moose\", 18, \"郑州\", \"小太阳\")\n",
    "stu(\"某某人\")\n",
    "# 收集参数可以不带任何实参调用，此时收集参数为空tuple\n",
    "stu()\n",
    "# 如果使用关键字参数格式调用，会出现问题\n",
    "stu(name=\"Moos\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 收集参数之关键字收集参数\n",
    "- 把关键字参数按照字典格式存入收集参数\n",
    "- 语法：\n",
    "\n",
    "        def func( **kwargs):\n",
    "           func_body\n",
    "           \n",
    "        # 调用：\n",
    "        func(p1=v1, p2=v2 ,p3=v3 ....)\n",
    "    - kwargs一般约定俗称\n",
    "    - 调用时，把多余关键字参数放入kwargs\n",
    "    - 访问kwargs需要使用字典格式访问\n",
    "    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好：\n",
      "<class 'dict'>\n",
      "name --- Moose\n",
      "age --- 19\n",
      "addr --- 郑州\n",
      "********************\n",
      "Hello 大家好：\n",
      "<class 'dict'>\n",
      "name --- 某某人\n"
     ]
    }
   ],
   "source": [
    "# 调用的时候需要使用关键字参数调用\n",
    "def stu( **kwargs):\n",
    "    print(\"Hello 大家好：\")\n",
    "    print(type(kwargs))\n",
    "    # 对于字典的访问，python2 和python3有区别\n",
    "    for k,v in kwargs.items():\n",
    "        print(k, \"---\", v)\n",
    "\n",
    "stu(name=\"Moose\", age=19, addr=\"郑州\")\n",
    "print(\"*\" * 20)\n",
    "stu(name=\"某某人\") "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 收集参数混合调用的顺序问题\n",
    "- 收集参数，关键字参数，普通参数可以混合使用；\n",
    "- 使用规则就是，普通参数和关键字参数优先；\n",
    "- 定义顺序：普通参数，收集参数tuple，关键字参数，收集参数dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫Moose，今年19岁\n",
      "我没有爱好\n",
      "******************************\n",
      "我叫Moose，今年19岁\n",
      "我的爱好是爱好1\n",
      "甲乙\n",
      "丙丁\n",
      "hobby1 --- 做饭\n",
      "hobby2 --- 睡觉\n",
      "******************************\n"
     ]
    }
   ],
   "source": [
    "# 收集参数混合调用实例：\n",
    "def stu(name, age, *args, hobby=\"没有\", **kwargs):\n",
    "    print(\"我叫{0}，今年{1}岁\".format(name, age))\n",
    "    if hobby == \"没有\":\n",
    "        print(\"我没有爱好\")\n",
    "    else:\n",
    "        print(\"我的爱好是{0}\".format(hobby))\n",
    "    \n",
    "    for i in args:\n",
    "        print(i)\n",
    "        \n",
    "    for k,v in kwargs.items():\n",
    "        print(k, \"---\", v)\n",
    "    print(\"*\" * 30)\n",
    "    \n",
    "# 开始调用\n",
    "name = \"Moose\"\n",
    "age = 19\n",
    "stu(name, age)\n",
    "\n",
    "stu(name, age, \"甲乙\", \"丙丁\", hobby=\"爱好1\", hobby1=\"做饭\", hobby2=\"睡觉\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 收集参数的解包问题\n",
    "- 把参数放入List或字典中，直接把List/dict的值放入收集参数中；\n",
    "- 未解包是，收集参数会将传入List/dict的整体当做一个对象；\n",
    "- 针对tuple(list)，调用前加入*号；\n",
    "- 针对dict解包，调用前加入两个*号；"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "哈哈哈\n",
      "['liuying', 30, 230]\n",
      "******************************\n",
      "哈哈哈\n",
      "liuying\n",
      "30\n",
      "230\n",
      "******************************\n"
     ]
    }
   ],
   "source": [
    "# 解包问题\n",
    "def stu(*args):\n",
    "    print(\"哈哈哈\")\n",
    "    for i in args:\n",
    "        print(i)\n",
    "    print(\"*\" * 30)\n",
    "        \n",
    "l = list()\n",
    "l.append(\"liuying\")\n",
    "l.append(30)\n",
    "l.append(230)\n",
    "\n",
    "stu(l)\n",
    "stu(*l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 返回值\n",
    "- 函数和过程的区别\n",
    "    - 有无返回值\n",
    "- 需要用return显示返回内容；\n",
    "- 如果没有返回值，会默认为None；\n",
    "- 推荐写法，无论有无返回值，最后都要以return结束；\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "有返回值\n",
      "1\n",
      "无返回值\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "# 示例\n",
    "\n",
    "def func_1():\n",
    "    print(\"有返回值\")\n",
    "    return 1\n",
    "\n",
    "def func_2():\n",
    "    print(\"无返回值\")\n",
    "    \n",
    "f1 = func_1()\n",
    "print(f1)\n",
    "\n",
    "f2 = func_2()\n",
    "print(f2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 函数文档\n",
    "- 函数的文档作用是对当前函数提供使用的参考信息\n",
    "- 文档的写法：\n",
    "    - 在函数内部开始的第一行使用三字符串定义符；\n",
    "    - 一般具有特定格式；\n",
    "- 文档查看\n",
    "    - 使用help函数，形如help(func)；\n",
    "    - 使用__doc__，参考案例；\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function stu in module __main__:\n",
      "\n",
      "stu(name, age, *args)\n",
      "    这是文档\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n    这是文档\\n    '"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 文档案例\n",
    "def stu(name, age, *args):\n",
    "    '''\n",
    "    这是文档\n",
    "    '''\n",
    "    print(\"This is 函数 stu\")\n",
    "\n",
    "help(stu)\n",
    "stu.__doc__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
